package com.gitee.ed.pattern.proxy;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.StringJoiner;

/**
 * 代理调用信息
 *
 * @author hongda.li
 */
public class Invocation<Target> {
    /**
     * 代理目标接口类型
     */
    private final Class<Target> target;
    /**
     * 代理实例
     */
    private final Target proxy;
    /**
     * 代理方法
     */
    private final Method method;
    /**
     * 代理参数
     */
    private final Object[] args;
    /**
     * 执行结果
     */
    private Object result;
    /**
     * 可能出现的异常
     */
    private Exception exception;

    /**
     * 构建一个调用信息
     *
     * @param target 代理目标接口
     * @param proxy  代理目标的实现类
     * @param method 调用方法
     * @param args   方法参数
     */
    public Invocation(Class<Target> target,
                      Target proxy,
                      Method method,
                      Object[] args) {
        this.target = target;
        this.proxy = proxy;
        this.method = method;
        this.args = args;
    }

    public Method getMethod() {
        return method;
    }

    public Object[] getArgs() {
        return args;
    }

    public Exception getException() {
        return exception;
    }

    public void setException(Exception exception) {
        this.exception = exception;
    }

    public Target getProxy() {
        return proxy;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    public Class<Target> getTarget() {
        return target;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Invocation<?> that = (Invocation<?>) o;
        return Objects.equals(target, that.target)
                && Objects.equals(proxy, that.proxy)
                && Objects.equals(method, that.method)
                && Objects.deepEquals(args, that.args)
                && Objects.equals(exception, that.exception)
                && Objects.equals(result, that.result);
    }

    @Override
    public int hashCode() {
        return Objects.hash(target, proxy, method, exception, result, Arrays.hashCode(args));
    }

    @Override
    public String toString() {
        return new StringJoiner(", ", Invocation.class.getSimpleName() + "[", "]")
                .add("args=" + Arrays.toString(args))
                .add("target=" + target)
                .add("proxy=" + proxy)
                .add("method=" + method)
                .add("throwable=" + exception)
                .add("result=" + result)
                .toString();
    }
}